// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.commons.ui.swt;

import java.util.HashMap;
import java.util.Map;

import org.dengues.commons.i18n.Messages;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableTree;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.ColorDialog;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.Tree;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf 2008-1-7 qiang.zhang $
 * 
 */
public class ColorCombo extends Composite {

    public enum EColorImages {
        WHITE(Display.getDefault().getSystemColor(SWT.COLOR_WHITE).getRGB(), Messages.getString("ColorCombo.white")), //$NON-NLS-1$
        BLACK(Display.getDefault().getSystemColor(SWT.COLOR_BLACK).getRGB(), Messages.getString("ColorCombo.black")), //$NON-NLS-1$
        RED(Display.getDefault().getSystemColor(SWT.COLOR_RED).getRGB(), Messages.getString("ColorCombo.red")), //$NON-NLS-1$
        GREEN(Display.getDefault().getSystemColor(SWT.COLOR_GREEN).getRGB(), Messages.getString("ColorCombo.green")), //$NON-NLS-1$
        BLUE(Display.getDefault().getSystemColor(SWT.COLOR_BLUE).getRGB(), Messages.getString("ColorCombo.blue")), //$NON-NLS-1$
        YELLOW(Display.getDefault().getSystemColor(SWT.COLOR_YELLOW).getRGB(), Messages.getString("ColorCombo.yellow")), //$NON-NLS-1$
        CYAN(Display.getDefault().getSystemColor(SWT.COLOR_CYAN).getRGB(), Messages.getString("ColorCombo.cyan")), //$NON-NLS-1$
        MAGENTA(Display.getDefault().getSystemColor(SWT.COLOR_MAGENTA).getRGB(), Messages.getString("ColorCombo.magenta")), //$NON-NLS-1$
        GRAY(Display.getDefault().getSystemColor(SWT.COLOR_GRAY).getRGB(), Messages.getString("ColorCombo.gray")), //$NON-NLS-1$

        CUSTOME(null, Messages.getString("ColorCombo.customize")); //$NON-NLS-1$

        private RGB rgb;

        private String displayName;

        EColorImages(RGB rgb, String displayName) {
            this.rgb = rgb;
            this.displayName = displayName;
        }

        public String rgbString() {
            return "(" + rgb.red + "," + rgb.green + "," + rgb.blue + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
        }

        /**
         * Getter for rgb.
         * 
         * @return the rgb
         */
        public RGB getRgb() {
            return this.rgb;
        }

        /**
         * Getter for displayName.
         * 
         * @return the displayName
         */
        public String getDisplayName() {
            return this.displayName;
        }
    }

    private final Map<EColorImages, Image> colorImages = new HashMap<EColorImages, Image>();

    /**
     * The default extent in pixels.
     */
    private static final int DEFAULT_EXTENT = 16;

    /**
     * The label widget showing the current color.
     */
    private Label colorLabel;

    /**
     * The label widget showing the RGB values.
     */
    private Label rgbLabel;

    private Button arrow;

    /**
     * The image.
     */
    private Image curImage;

    private RGB curRGB;

    private Menu menu;

    /**
     * Qiang.Zhang.Adolf@gmail.com ColorCombo constructor comment.
     * 
     * @param parent
     * @param style
     */
    public ColorCombo(Composite parent, int style) {
        super(parent, style);
        GridLayout gridLayout = new GridLayout();
        gridLayout.marginBottom = 0;
        gridLayout.marginHeight = 0;
        gridLayout.marginLeft = 0;
        gridLayout.marginRight = 0;
        gridLayout.marginTop = 0;
        gridLayout.marginWidth = 0;
        gridLayout.numColumns = 3;
        gridLayout.horizontalSpacing = 0;
        setLayout(gridLayout);
        for (EColorImages colorImage : EColorImages.values()) {
            RGB rgb = colorImage.getRgb();
            if (rgb != null) {
                colorImages.put(colorImage, createColorImage(getParent(), rgb));
            }
        }
        initChildren();
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "initChildren".
     */
    private void initChildren() {
        colorLabel = new Label(this, SWT.NONE);
        rgbLabel = new Label(this, SWT.NONE);
        curRGB = EColorImages.WHITE.getRgb();
        colorLabel.setImage(colorImages.get(EColorImages.WHITE));
        rgbLabel.setText(getRGBText());

        GridData gridData = new GridData();
        gridData.widthHint = 78;
        rgbLabel.setLayoutData(gridData);
        arrow = new Button(this, SWT.ARROW | SWT.DOWN);
        arrow.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                Rectangle rect = getBounds();
                Point pt = getParent().toDisplay(new Point(rect.x, rect.y));
                getColorMenu().setLocation(pt.x, pt.y + rect.height);
                getColorMenu().setVisible(true);
            }

        });
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getRGBText".
     * 
     * @return
     */
    private String getRGBText() {
        return "(" + curRGB.red + "," + curRGB.green + "," + curRGB.blue + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
    }

    public Menu getColorMenu() {
        if (menu == null) {
            menu = new Menu(this.getShell(), SWT.NONE);
            for (int i = 0; i < EColorImages.values().length; i++) {
                MenuItem blackItem = new MenuItem(menu, SWT.NONE);
                EColorImages itemImage = EColorImages.values()[i];
                blackItem.setData(itemImage);
                if (colorImages.get(itemImage) != null) {
                    blackItem.setImage(colorImages.get(itemImage));
                }
                blackItem.setText(itemImage.getDisplayName());
                blackItem.addSelectionListener(new SelectionAdapter() {

                    @Override
                    public void widgetSelected(SelectionEvent e) {
                        EColorImages item = (EColorImages) ((MenuItem) e.getSource()).getData();
                        switch (item) {
                        case GREEN:
                        case RED:
                        case WHITE:
                        case BLUE:
                        case BLACK:
                        case YELLOW:
                        case CYAN:
                        case GRAY:
                        case MAGENTA:
                            curRGB = item.getRgb();
                            colorLabel.setImage(colorImages.get(item));
                            rgbLabel.setText(getRGBText());
                            break;
                        case CUSTOME:
                            ColorDialog colorDialog = new ColorDialog(getShell());
                            curRGB = colorDialog.open();
                            if (curRGB != null) {
                                disposeImage();
                                curImage = createColorImage(getShell(), curRGB);
                                colorLabel.setImage(curImage);
                                rgbLabel.setText(getRGBText());
                            }
                            break;
                        default:
                            break;
                        }
                    }
                });
            }
        }
        return menu;
    }

    private void disposeImage() {
        if (curImage != null) {
            if (!curImage.isDisposed()) {
                curImage.dispose();
            }
            curImage = null;
        }
    }

    private Image createColorImage(Control w, RGB color) {
        GC gc = new GC(w);
        FontMetrics fm = gc.getFontMetrics();
        int size = fm.getAscent();
        gc.dispose();

        int indent = 6;
        int extent = DEFAULT_EXTENT;
        if (w instanceof Table) {
            extent = ((Table) w).getItemHeight() - 1;
        } else if (w instanceof Tree) {
            extent = ((Tree) w).getItemHeight() - 1;
        } else if (w instanceof TableTree) {
            extent = ((TableTree) w).getItemHeight() - 1;
        }

        if (size > extent) {
            size = extent;
        }

        int width = indent + size;
        int height = extent;

        int xoffset = indent;
        int yoffset = (height - size) / 2;

        RGB black = new RGB(0, 0, 0);
        PaletteData dataPalette = new PaletteData(new RGB[] { black, black, color });
        ImageData data = new ImageData(width, height, 4, dataPalette);
        data.transparentPixel = 0;

        int end = size - 1;
        for (int y = 0; y < size; y++) {
            for (int x = 0; x < size; x++) {
                if (x == 0 || y == 0 || x == end || y == end) {
                    data.setPixel(x + xoffset, y + yoffset, 1);
                } else {
                    data.setPixel(x + xoffset, y + yoffset, 2);
                }
            }
        }
        ImageData mask = data.getTransparencyMask();
        Image newimage = new Image(getDisplay(), data, mask);
        return newimage;
    }

    /**
     * Getter for curRGB.
     * 
     * @return the curRGB
     */
    public RGB getCurRGB() {
        return this.curRGB;
    }
}
